# encoding:utf-8

# 基于 pyctp 库实现的 TraderApi
# 保持与原版 TraderApi.py 接口一致
# import asyncio
# asyncio.get_event_loop().set_debug(True)  # 启用详细调试信息
# import debugpy

from time import sleep, perf_counter as timer
from datetime import datetime

from queue import Queue, Empty
from .hlog import HLog
import re

#包含上一级目录父目录
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
import thosttraderapi as traderapi

# 创建logger实例，使用pyctp_yymmdd_hhmmss.log格式
timestamp = datetime.now().strftime("%y%m%d_%H%M")
logger = HLog(name=f"pyctp_traderapi_{timestamp}")


# 常量定义 - 保持与原版一致
Direction_Buy = '0'
Direction_Sell = '1'
OffsetFlag_Open = '0'
OffsetFlag_Close = '1'
OffsetFlag_ForceClose = '2'
OffsetFlag_CloseToday = '3'
OffsetFlag_CloseYesterday = '4'

OrderStatus_AllTraded = '0'
OrderStatus_PartTradedQueueing = '1'
OrderStatus_PartTradedNotQueueing = '2'
OrderStatus_NoTradeQueueing = '3'
OrderStatus_NoTradeNotQueueing = '4'
OrderStatus_Canceled = '5'
OrderStatus_Unknown = 'a'
OrderStatus_NotTouched = 'b'
OrderStatus_Touched = 'c'

OrderSubmitStatus_InsertSubmitted = '0'
OrderSubmitStatus_CancelSubmitted = '1'
OrderSubmitStatus_ModifySubmitted = '2'
OrderSubmitStatus_Accepted = '3'
OrderSubmitStatus_InsertRejected = '4'
OrderSubmitStatus_CancelRejected = '5'
OrderSubmitStatus_ModifyRejected = '6'


def to_str(data,code='utf-8'):
    """转换为字符串"""
    if isinstance(data, bytes):
        return data.decode(code, errors='ignore')
    return str(data)


def to_bytes(data, code='gbk', max_len=None):
    """转换为字节，并确保符合CTP字段长度要求"""
    if isinstance(data, str):
        encoded = data.encode(code)
    else:
        encoded = data
    
    if max_len is not None:
        # 确保不超过最大长度，并用null字节填充
        if len(encoded) >= max_len:
            encoded = encoded[:max_len-1]  # 留一个字节给null终止符
        encoded = encoded + b'\x00' * (max_len - len(encoded))
    
    return encoded


class TraderApiBase(traderapi.CThostFtdcTraderSpi):
    """基于 pyctp 的交易 API 基础类"""
    
    def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None,
                 page_dir='', private_resume_type=2, public_resume_type=2):
        super().__init__()
        
        # 基本参数
        self.broker_id = broker_id
        self.td_server = td_server
        self.investor_id = investor_id
        self.password = password
        self.app_id = app_id
        self.auth_code = auth_code
        self.md_queue = md_queue
        self.page_dir = page_dir
        self.private_resume_type = private_resume_type
        self.public_resume_type = public_resume_type
        
        # 状态变量
        self.is_connected = False
        self.is_logged_in = False
        self.request_id = 0
        self.status = 0
        
        # 创建 API 实例
        self.trader_api = traderapi.CThostFtdcTraderApi.CreateFtdcTraderApi(page_dir)
        self.trader_api.RegisterSpi(self)
        self.trader_api.SubscribePrivateTopic(private_resume_type)
        self.trader_api.SubscribePublicTopic(public_resume_type)
        self.trader_api.RegisterFront(td_server)
        
        # 启动 API
        self.trader_api.Init()
    
    def get_next_request_id(self):
        """获取下一个请求ID"""
        self.request_id += 1
        return self.request_id
    
    def write_log(self, msg, data=None):
        """写日志"""
        logger.info(f"[TraderApi] {msg}")
        if data:
            logger.info(f"[TraderApi] Data: {data}")
    
    def Join(self):
        """等待API结束并处理业务逻辑"""
        while True:
            if self.status == 0:
                if self.md_queue is not None:
                    try:
                        while not self.md_queue.empty():
                            last_md = self.md_queue.get(block=False)
                            self.md_dict[last_md['InstrumentID']] = last_md
                    except Empty:
                        pass

                self.process_rtn_order()
                self.process_rtn_trade()
                self.check_position()
            else:
                sleep(1)
    
    def Release(self):
        """释放API"""
        self.trader_api.Release()
    
    # 基础回调方法
    def OnFrontConnected(self):
        """前置机连接成功回调"""
        logger.info("OnFrontConnected")
        self.is_connected = True
        
        # 认证
        auth_field = traderapi.CThostFtdcReqAuthenticateField()
        # 确保字段为字符串类型
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        app_id = self.app_id.decode() if isinstance(self.app_id, bytes) else self.app_id
        auth_code = self.auth_code.decode() if isinstance(self.auth_code, bytes) else self.auth_code
        
        auth_field.BrokerID = broker_id
        auth_field.UserID = investor_id
        auth_field.AppID = app_id
        auth_field.AuthCode = auth_code
        
        logger.info(f"发送认证请求: BrokerID={broker_id}, UserID={investor_id}")
        result = self.trader_api.ReqAuthenticate(auth_field, self.get_next_request_id())
        logger.info(f"认证请求结果: {result}")
    
    def OnFrontDisconnected(self, nReason):
        """前置机连接断开回调"""
        logger.warning(f"OnFrontDisconnected: 连接断开，原因代码={nReason}")
        self.is_connected = False
        self.is_logged_in = False
    
    def OnRspAuthenticate(self, pRspAuthenticateField, pRspInfo, nRequestID, bIsLast):
        """认证响应回调"""
        logger.info(f"OnRspAuthenticate: ErrorID={pRspInfo.ErrorID if pRspInfo else 'None'}")
        if pRspInfo and pRspInfo.ErrorID != 0:
            logger.error(f"认证失败: {pRspInfo.ErrorMsg}")
            return
        
        logger.info("认证成功，开始登录")
        # 登录
        login_field = traderapi.CThostFtdcReqUserLoginField()
        # 确保字段为字符串类型
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        password = self.password.decode() if isinstance(self.password, bytes) else self.password
        
        login_field.BrokerID = broker_id
        login_field.UserID = investor_id
        login_field.Password = password
        login_field.UserProductInfo = ""
        
        logger.info(f"发送登录请求: BrokerID={broker_id}, UserID={investor_id}")
        result = self.trader_api.ReqUserLogin(login_field, self.get_next_request_id())
        logger.info(f"登录请求结果: {result}")
    
    def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast):
        """登录响应"""
        if pRspInfo and pRspInfo.ErrorID != 0:
            logger.error(f"登录失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")
            return
        
        logger.info("登录成功")
        self.is_logged_in = True
        
        if pRspUserLogin:
            logger.info(f"交易日: {to_str(pRspUserLogin.TradingDay)}")
        logger.info(f"会话ID: {pRspUserLogin.SessionID}")
        
        # 查询结算信息
        qry_settlement_field = traderapi.CThostFtdcQrySettlementInfoField()
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        qry_settlement_field.BrokerID = broker_id
        qry_settlement_field.InvestorID = investor_id
        if pRspUserLogin:
            qry_settlement_field.TradingDay = pRspUserLogin.TradingDay
        
        self.trader_api.ReqQrySettlementInfo(qry_settlement_field, self.get_next_request_id())
    
    def OnRspQrySettlementInfo(self, pSettlementInfo, pRspInfo, nRequestID, bIsLast):
        """查询结算信息响应"""
        if pSettlementInfo:
            logger.info(f"结算信息: {to_str(pSettlementInfo.Content)}")
        
        if bIsLast:
            # 确认结算信息
            confirm_field = traderapi.CThostFtdcSettlementInfoConfirmField()
            broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
            investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
            confirm_field.BrokerID = broker_id
            confirm_field.InvestorID = investor_id
            
            self.trader_api.ReqSettlementInfoConfirm(confirm_field, self.get_next_request_id())
    
    def OnRspSettlementInfoConfirm(self, pSettlementInfoConfirm, pRspInfo, nRequestID, bIsLast):
        """确认结算信息响应"""
        if pRspInfo and pRspInfo.ErrorID != 0:
            logger.error(f"确认结算信息失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")
        else:
            logger.info("确认结算信息成功")

    def OnRspQryInstrumentCommissionRate(self, pInstrumentCommissionRate, pRspInfo, nRequestID, bIsLast):
        """ 请求查询手续费响应 """ 
        pass

    def OnRspQryInstrumentOrderCommRate(self, pInstrumentOrderCommRate, pRspInfo, nRequestID, bIsLast):
        """ 请求查询报单手续费响应 """ 
        pass
    
    
    # 报单相关方法
    def ReqOrderInsert(self, order_field, request_id=None):
        """报单录入请求"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqOrderInsert(order_field, request_id)
    
    def ReqOrderAction(self, order_action_field, request_id=None):
        """报单操作请求"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqOrderAction(order_action_field, request_id)
    
    # 查询相关方法
    def ReqQryInstrument(self, qry_instrument_field, request_id=None):
        """查询合约"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqQryInstrument(qry_instrument_field, request_id)

    def ReqQryInstrumentCommissionRate(self, qry_instrument_field, request_id=None):
        """查询合约 手续费"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqQryInstrumentCommissionRate(qry_instrument_field, request_id)    
    
    def ReqQryInstrumentOrderCommRate(self, qry_instrument_order_comm_rate_field, request_id=None):
        """查询合约 报单手续费"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqQryInstrumentOrderCommRate(qry_instrument_order_comm_rate_field, request_id)    


    def ReqQryInvestorPosition(self, qry_position_field, request_id=None):
        """查询投资者持仓"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqQryInvestorPosition(qry_position_field, request_id)
    
    def ReqQryTradingAccount(self, qry_account_field, request_id=None):
        """查询资金账户"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqQryTradingAccount(qry_account_field, request_id)
    
    def ReqQryOrder(self, qry_order_field, request_id=None):
        """查询订单"""
        if request_id is None:
            request_id = self.get_next_request_id()
        return self.trader_api.ReqQryOrder(qry_order_field, request_id)

    def _convert_instrument_to_dict(self, pInstrument):
        """将合约对象转换为字典"""
        if not pInstrument:
            return {}
        
        try:
            # 只使用实际存在的属性
            result = {}
            
            # 基本信息
            if hasattr(pInstrument, 'InstrumentID'):
                result['InstrumentID'] = to_str(pInstrument.InstrumentID)
            if hasattr(pInstrument, 'ExchangeID'):
                result['ExchangeID'] = to_str(pInstrument.ExchangeID)
            if hasattr(pInstrument, 'InstrumentName'):
                result['InstrumentName'] = to_str(pInstrument.InstrumentName)
            if hasattr(pInstrument, 'ProductID'):
                result['ProductID'] = to_str(pInstrument.ProductID)
            if hasattr(pInstrument, 'ExchangeInstID'):
                result['ExchangeInstID'] = to_str(pInstrument.ExchangeInstID)
            
            # 价格和数量信息
            if hasattr(pInstrument, 'PriceTick'):
                result['PriceTick'] = pInstrument.PriceTick
            if hasattr(pInstrument, 'VolumeMultiple'):
                result['VolumeMultiple'] = pInstrument.VolumeMultiple
            if hasattr(pInstrument, 'MinLimitOrderVolume'):
                result['MinLimitOrderVolume'] = pInstrument.MinLimitOrderVolume
            if hasattr(pInstrument, 'MaxLimitOrderVolume'):
                result['MaxLimitOrderVolume'] = pInstrument.MaxLimitOrderVolume
            if hasattr(pInstrument, 'MinMarketOrderVolume'):
                result['MinMarketOrderVolume'] = pInstrument.MinMarketOrderVolume
            if hasattr(pInstrument, 'MaxMarketOrderVolume'):
                result['MaxMarketOrderVolume'] = pInstrument.MaxMarketOrderVolume
            
            # 保证金信息
            if hasattr(pInstrument, 'LongMarginRatio'):
                result['LongMarginRatio'] = pInstrument.LongMarginRatio
            if hasattr(pInstrument, 'ShortMarginRatio'):
                result['ShortMarginRatio'] = pInstrument.ShortMarginRatio
            
            # 交易状态
            if hasattr(pInstrument, 'IsTrading'):
                result['IsTrading'] = pInstrument.IsTrading
            if hasattr(pInstrument, 'InstLifePhase'):
                result['InstLifePhase'] = pInstrument.InstLifePhase
            
            # 日期信息
            if hasattr(pInstrument, 'CreateDate'):
                result['CreateDate'] = to_str(pInstrument.CreateDate)
            if hasattr(pInstrument, 'OpenDate'):
                result['OpenDate'] = to_str(pInstrument.OpenDate)
            if hasattr(pInstrument, 'ExpireDate'):
                result['ExpireDate'] = to_str(pInstrument.ExpireDate)
            if hasattr(pInstrument, 'StartDelivDate'):
                result['StartDelivDate'] = to_str(pInstrument.StartDelivDate)
            if hasattr(pInstrument, 'EndDelivDate'):
                result['EndDelivDate'] = to_str(pInstrument.EndDelivDate)
            if hasattr(pInstrument, 'DeliveryYear'):
                result['DeliveryYear'] = pInstrument.DeliveryYear
            if hasattr(pInstrument, 'DeliveryMonth'):
                result['DeliveryMonth'] = pInstrument.DeliveryMonth
            
            # 期权相关
            if hasattr(pInstrument, 'OptionsType'):
                result['OptionsType'] = pInstrument.OptionsType
            if hasattr(pInstrument, 'StrikePrice'):
                result['StrikePrice'] = pInstrument.StrikePrice
            if hasattr(pInstrument, 'UnderlyingInstrID'):
                result['UnderlyingInstrID'] = to_str(pInstrument.UnderlyingInstrID)
            if hasattr(pInstrument, 'UnderlyingMultiple'):
                result['UnderlyingMultiple'] = pInstrument.UnderlyingMultiple
            
            # 其他信息
            if hasattr(pInstrument, 'ProductClass'):
                result['ProductClass'] = pInstrument.ProductClass
            if hasattr(pInstrument, 'PositionType'):
                result['PositionType'] = pInstrument.PositionType
            if hasattr(pInstrument, 'PositionDateType'):
                result['PositionDateType'] = pInstrument.PositionDateType
            if hasattr(pInstrument, 'CombinationType'):
                result['CombinationType'] = pInstrument.CombinationType
            if hasattr(pInstrument, 'MaxMarginSideAlgorithm'):
                result['MaxMarginSideAlgorithm'] = pInstrument.MaxMarginSideAlgorithm
            
            return result
            
        except AttributeError as e:
            logger.error(f"AttributeError in _convert_instrument_to_dict: {e}")
            logger.error(f"pInstrument type: {type(pInstrument)}")
            if hasattr(pInstrument, '__dict__'):
                logger.error(f"pInstrument attributes: {dir(pInstrument)}")
            return {}
        except Exception as e:
            logger.error(f"Unexpected error in _convert_instrument_to_dict: {e}")
            return {}

    def _convert_commissionRate_to_dict(self, pCommissionRate):
        """
        将CThostFtdcInstrumentCommissionRateField对象转换为字典格式
        
        Args:
            pCommissionRate: CThostFtdcInstrumentCommissionRateField类型的对象
            
        Returns:
            dict: 包含手续费信息的字典
        """
        try:
            result = {}
            
            # 基本标识信息
            if hasattr(pCommissionRate, 'InstrumentID'):
                result['InstrumentID'] = to_str(pCommissionRate.InstrumentID)
            if hasattr(pCommissionRate, 'InvestorRange'):
                result['InvestorRange'] = pCommissionRate.InvestorRange
            if hasattr(pCommissionRate, 'BrokerID'):
                result['BrokerID'] = to_str(pCommissionRate.BrokerID)
            if hasattr(pCommissionRate, 'InvestorID'):
                result['InvestorID'] = to_str(pCommissionRate.InvestorID)
            
            # 开仓手续费
            if hasattr(pCommissionRate, 'OpenRatioByMoney'):
                result['OpenRatioByMoney'] = pCommissionRate.OpenRatioByMoney
            if hasattr(pCommissionRate, 'OpenRatioByVolume'):
                result['OpenRatioByVolume'] = pCommissionRate.OpenRatioByVolume
            
            # 平仓手续费
            if hasattr(pCommissionRate, 'CloseRatioByMoney'):
                result['CloseRatioByMoney'] = pCommissionRate.CloseRatioByMoney
            if hasattr(pCommissionRate, 'CloseRatioByVolume'):
                result['CloseRatioByVolume'] = pCommissionRate.CloseRatioByVolume
            
            # 平今手续费
            if hasattr(pCommissionRate, 'CloseTodayRatioByMoney'):
                result['CloseTodayRatioByMoney'] = pCommissionRate.CloseTodayRatioByMoney
            if hasattr(pCommissionRate, 'CloseTodayRatioByVolume'):
                result['CloseTodayRatioByVolume'] = pCommissionRate.CloseTodayRatioByVolume
            
            # 其他信息
            if hasattr(pCommissionRate, 'ExchangeID'):
                result['ExchangeID'] = to_str(pCommissionRate.ExchangeID)
            if hasattr(pCommissionRate, 'BizType'):
                result['BizType'] = pCommissionRate.BizType
            
            return result
            
        except AttributeError as e:
            logger.error(f"AttributeError in _convert_commissionRate_to_dict: {e}")
            logger.error(f"pCommissionRate type: {type(pCommissionRate)}")
            if hasattr(pCommissionRate, '__dict__'):
                logger.error(f"pCommissionRate attributes: {dir(pCommissionRate)}")
            return {}
        except Exception as e:
            logger.error(f"Unexpected error in _convert_commissionRate_to_dict: {e}")
            return {}

    def _convert_order_commission_to_dict(self, pInstrumentOrderCommRate):
        """
        将CThostFtdcInstrumentOrderCommRateField对象转换为字典格式
        
        Args:
            pInstrumentOrderCommRate: CThostFtdcInstrumentOrderCommRateField类型的对象
            
        Returns:
            dict: 包含报单手续费信息的字典
        """
        try:
            result = {}
            
            # 基本标识信息
            if hasattr(pInstrumentOrderCommRate, 'InstrumentID'):
                result['InstrumentID'] = to_str(pInstrumentOrderCommRate.InstrumentID)
            if hasattr(pInstrumentOrderCommRate, 'InvestorRange'):
                result['InvestorRange'] = pInstrumentOrderCommRate.InvestorRange
            if hasattr(pInstrumentOrderCommRate, 'BrokerID'):
                result['BrokerID'] = to_str(pInstrumentOrderCommRate.BrokerID)
            if hasattr(pInstrumentOrderCommRate, 'InvestorID'):
                result['InvestorID'] = to_str(pInstrumentOrderCommRate.InvestorID)
            
            # 报单手续费    
            if hasattr(pInstrumentOrderCommRate, 'OrderCommRate'):
                result['OrderCommByVolume'] = pInstrumentOrderCommRate.OrderCommByVolume
            if hasattr(pInstrumentOrderCommRate, 'OrderActionCommByVolume'):
                result['OrderActionCommByVolume'] = pInstrumentOrderCommRate.OrderActionCommByVolume
            return result
        
        except Exception as e:
            logger.error(f"Unexpected error in _convert_order_commission_to_dict: {e}")
            return {}


class TraderApi(TraderApiBase):
    """交易API实现类，保持与原版接口一致"""
    
    def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None,
                 page_dir='', private_resume_type=2, public_resume_type=2):
        super().__init__(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue,
                        page_dir, private_resume_type, public_resume_type)
        
        # 初始化额外参数
        self.init_extra()
    
    def init_extra(self):
        """初始化策略参数"""
        
        self.rtn_order_list = []
        self.last_rtn_order_index = 0  # 已处理报单ID
        self.rtn_trade_list = []
        self.last_rtn_trade_index = 0  # 已处理成交ID

        # 订单和交易相关字典
        self.order_dict = {}  # 订单字典
        self.trade_dict = {}  # 交易字典
        self.md_dict = {}  # 行情数据字典
        self.server_time_dict = {}  # 服务器时间字典
        self.position_dict = {}  # 持仓字典
        self.local_position_dict = {}  # 本地持仓字典
        self.action_num_dict = {}  # 撤单次数字典
        self.pl_parameter_dict = {}  # 止盈止损参数字典

        # 从队列获取策略参数
        if self.md_queue:
            try:
                parameter_dict = self.md_queue.get(block=False)
                self.id = parameter_dict.get('StrategyID', 1)
                self.order_ref = self.id * 10000
                self.order_ref_range = [self.order_ref, self.order_ref + 10000]
                self.pl_parameter_dict = parameter_dict.get('ProfitLossParameter', {})
            except Empty:
                # 如果队列为空，使用默认值
                self.id = 1
                self.order_ref = self.id * 10000
                self.order_ref_range = [self.order_ref, self.order_ref + 10000]
        else:
            self.id = 1
            self.order_ref = self.id * 10000
            self.order_ref_range = [self.order_ref, self.order_ref + 10000]

    def get_price(self, instrument_id, direction, price_type=0):
        """
        获取报单价格
        :param instrument_id: 合约
        :param direction: 持仓方向
        :param price_type: 0->对手价, 1->排队价, 2->市价
        :return: 报单价格
        """
        result = None
        try:
            md = self.md_dict[instrument_id]
            if price_type == 0:  # 对手价
                result = md['BidPrice1'] if direction == Direction_Sell else md['AskPrice1']
            elif price_type == 1:  # 排队价
                result = md['AskPrice1'] if direction == Direction_Sell else md['BidPrice1']
            elif price_type == 2:  # 市价
                result = md['LowerLimitPrice'] if direction == Direction_Sell else md['UpperLimitPrice']
        except Exception as err_msg:
            self.write_log('get_price', err_msg)
        finally:
            return result

    def is_my_order(self, order_ref):
        """判断是否为本策略订单"""
        try:
            order_ref_int = int(order_ref)
            return self.order_ref_range[0] <= order_ref_int < self.order_ref_range[1]
        except:
            return True

    # 报单回调方法
    def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast):
        """录入报单回报"""
        if pInputOrder and self.is_my_order(pInputOrder.OrderRef):
            if pRspInfo and pRspInfo.ErrorID != 0:
                # 转换为字典格式保持兼容性
                order_dict = self._convert_order_to_dict(pInputOrder)
                self.on_order_insert_fail(order_dict)
            self.write_log(f"OnRspOrderInsert: {pRspInfo.ErrorID if pRspInfo else 0}", pInputOrder)

    def OnErrRtnOrderInsert(self, pInputOrder, pRspInfo):
        """订单错误通知"""
        if pInputOrder and self.is_my_order(pInputOrder.OrderRef):
            if pRspInfo and pRspInfo.ErrorID != 0:
                order_dict = self._convert_order_to_dict(pInputOrder)
                self.on_order_insert_fail(order_dict)
            self.write_log(f"OnErrRtnOrderInsert: {pRspInfo.ErrorID if pRspInfo else 0}", pInputOrder)

    def on_order_insert_fail(self, pOrder):
        """报单失败处理逻辑"""
        pass

    def OnRspOrderAction(self, pInputOrderAction, pRspInfo, nRequestID, bIsLast):
        """录入撤单回报"""
        if pInputOrderAction and self.is_my_order(pInputOrderAction.OrderRef):
            if pRspInfo and pRspInfo.ErrorID != 0:
                action_dict = self._convert_order_action_to_dict(pInputOrderAction)
                self.on_order_action_fail(action_dict)
            self.write_log(f"OnRspOrderAction: {pRspInfo.ErrorID if pRspInfo else 0}", pInputOrderAction)

    def on_order_action_fail(self, pInputOrderAction):
        """撤单失败处理逻辑"""
        pass

    def OnRtnOrder(self, pOrder):
        """订单状态变化通知"""
        if pOrder and self.is_my_order(pOrder.OrderRef):
            order_dict = self._convert_order_to_dict(pOrder)
            self.rtn_order_list.append(order_dict)

    def process_rtn_order(self):
        """处理订单回报"""
        try:
            last_rtn_order_index = len(self.rtn_order_list)
            for rtn_order in self.rtn_order_list[self.last_rtn_order_index:last_rtn_order_index]:
                # 未成交
                if rtn_order['OrderStatus'] == OrderStatus_NoTradeQueueing:
                    pass

                # 全部成交或部分成交
                elif rtn_order['OrderStatus'] == OrderStatus_AllTraded or rtn_order['OrderStatus'] == OrderStatus_PartTradedQueueing:
                    self.on_order_traded(rtn_order)

                # 撤单成功
                elif rtn_order['OrderStatus'] == OrderStatus_Canceled:
                    if rtn_order['InstrumentID'] in self.action_num_dict.keys():
                        self.action_num_dict[rtn_order['InstrumentID']] += 1
                    else:
                        self.action_num_dict[rtn_order['InstrumentID']] = 1
                    self.on_order_action(rtn_order)

                # 委托失败
                elif rtn_order['OrderSubmitStatus'] == OrderSubmitStatus_InsertRejected:
                    self.on_order_insert_fail(rtn_order)

                # 撤单失败
                elif rtn_order['OrderSubmitStatus'] == OrderSubmitStatus_CancelRejected:
                    self.on_order_action_fail(rtn_order)

                self.write_log(to_str(rtn_order.get('StatusMsg', '')), rtn_order)
            self.last_rtn_order_index = last_rtn_order_index
        except Exception as err_msg:
            self.write_log('process_rtn_order', str(err_msg))

    def on_order_traded(self, pOrder):
        """订单成交处理"""
        pass

    def on_order_action(self, pOrder):
        """撤单处理"""
        pass

    def OnRtnTrade(self, pTrade):
        """成交通知"""
        if pTrade and self.is_my_order(pTrade.OrderRef):
            trade_dict = self._convert_trade_to_dict(pTrade)
            self.rtn_trade_list.append(trade_dict)

    def process_rtn_trade(self):
        """处理成交回报"""
        try:
            last_rtn_trade_index = len(self.rtn_trade_list)
            for rtn_trade in self.rtn_trade_list[self.last_rtn_trade_index:last_rtn_trade_index]:

                rtn_trade['IsLock'] = False
                rtn_trade['AnchorTime'] = timer()
                rtn_trade['StopProfitDict'] = {}
                rtn_trade['StopLossDict'] = {}
                
                if rtn_trade['InstrumentID'] not in self.local_position_dict.keys():
                    self.local_position_dict[rtn_trade['InstrumentID']] = {
                        'LongVolume': 0, 'LongVolumeToday': 0, 'LongVolumeYesterday': 0, 'LongPositionList': [],
                        'ShortVolume': 0, 'ShortVolumeToday': 0, 'ShortVolumeYesterday': 0, 'ShortPositionList': []
                    }
                
                local_position = self.local_position_dict[rtn_trade['InstrumentID']]

                if rtn_trade['OffsetFlag'] == OffsetFlag_Open:
                    self.update_stop_price(rtn_trade)
                    if rtn_trade['Direction'] == Direction_Buy:
                        local_position['LongVolume'] += rtn_trade['Volume']
                        local_position['LongPositionList'].append(rtn_trade)
                    elif rtn_trade['Direction'] == Direction_Sell:
                        local_position['ShortVolume'] += rtn_trade['Volume']
                        local_position['ShortPositionList'].append(rtn_trade)
                elif rtn_trade['Direction'] == Direction_Buy:
                    local_position['ShortVolume'] = max(local_position['ShortVolume'] - rtn_trade['Volume'], 0)
                elif rtn_trade['Direction'] == Direction_Sell:
                    local_position['LongVolume'] = max(local_position['LongVolume'] - rtn_trade['Volume'], 0)

            self.last_rtn_trade_index = last_rtn_trade_index
        except Exception as err_msg:
            self.write_log('process_rtn_trade', str(err_msg))

    def update_stop_price(self, position):
        """
        获取止盈止损阈值。止损类型参考https://7jia.com/1002.html
        :param position: 持仓信息
        :return:
        """
        try:
            if position['InstrumentID'] in self.pl_parameter_dict.keys():
                pl_dict = self.pl_parameter_dict[position['InstrumentID']]
                for pl_type, delta in pl_dict.items():
                    # 固定止盈
                    sgn = 1 if position['Direction'] == Direction_Buy else -1
                    if pl_type == '0':
                        position['StopProfitDict']['0'] = position['Price'] + delta[0] * sgn
                    # 固定止损
                    elif pl_type == '1':
                        position['StopLossDict']['1'] = position['Price'] - delta[0] * sgn
        except Exception as err_msg:
            self.write_log('update_stop_price', err_msg)

    def check_position(self):
        """
        检查所有持仓是否触发持仓阈值。
        """
        try:
            for instrument_id, position in self.local_position_dict.items():
                if instrument_id not in self.md_dict.keys():
                    break
                md = self.md_dict[instrument_id]
                for long_position in position['LongPositionList']:
                    if not long_position['IsLock']:
                        trigger = False
                        for stop_profit in long_position['StopProfitDict'].values():
                            if md['LastPrice'] > stop_profit:
                                trigger = True
                                break

                        if not trigger:
                            for stop_loss in long_position['StopLossDict'].values():
                                if md['LastPrice'] < stop_loss:
                                    trigger = True
                                    break

                        if trigger:
                            order_price = self.get_price(instrument_id, Direction_Sell)
                            if order_price is not None:
                                self.sell_close(long_position['ExchangeID'], instrument_id, order_price, long_position['Volume'])
                                long_position['IsLock'] = True

                for short_position in position['ShortPositionList']:
                    if not short_position['IsLock']:
                        trigger = False
                        for stop_profit in short_position['StopProfitDict'].values():
                            if md['LastPrice'] < stop_profit:
                                trigger = True
                                break

                        if not trigger:
                            for stop_loss in short_position['StopLossDict'].values():
                                if md['LastPrice'] > stop_loss:
                                    trigger = True
                                    break

                        if trigger:
                            order_price = self.get_price(instrument_id, Direction_Buy)
                            if order_price is not None:
                                self.buy_close(short_position['ExchangeID'], instrument_id, order_price, short_position['Volume'])
                                short_position['IsLock'] = True
        except Exception as err:
            self.write_log(err)

    # 便利方法
    def buy_open(self, exchange_id, instrument_id, price, volume):
        """买开"""
        return self._send_order(exchange_id, instrument_id, Direction_Buy, OffsetFlag_Open, price, volume)

    def sell_open(self, exchange_id, instrument_id, price, volume):
        """卖开"""
        return self._send_order(exchange_id, instrument_id, Direction_Sell, OffsetFlag_Open, price, volume)

    def buy_close(self, exchange_id, instrument_id, price, volume):
        """买平"""
        return self._send_order(exchange_id, instrument_id, Direction_Buy, OffsetFlag_Close, price, volume)

    def sell_close(self, exchange_id, instrument_id, price, volume):
        """卖平"""
        return self._send_order(exchange_id, instrument_id, Direction_Sell, OffsetFlag_Close, price, volume)

    def _send_order(self, exchange_id, instrument_id, direction, offset_flag, price, volume):
        """发送订单"""
        order_field = traderapi.CThostFtdcInputOrderField()
        
        # 确保字段为字符串类型
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        
        order_field.BrokerID = broker_id
        order_field.InvestorID = investor_id
        order_field.ExchangeID = exchange_id
        order_field.InstrumentID = instrument_id
        order_field.UserID = investor_id
        order_field.Direction = direction
        order_field.CombOffsetFlag = offset_flag
        order_field.CombHedgeFlag = '1'  # 投机
        order_field.LimitPrice = price
        order_field.VolumeTotalOriginal = volume
        order_field.OrderPriceType = traderapi.THOST_FTDC_OPT_LimitPrice
        order_field.ContingentCondition = traderapi.THOST_FTDC_CC_Immediately
        order_field.TimeCondition = traderapi.THOST_FTDC_TC_GFD
        order_field.VolumeCondition = traderapi.THOST_FTDC_VC_AV
        order_field.MinVolume = 1
        order_field.ForceCloseReason = traderapi.THOST_FTDC_FCC_NotForceClose
        order_field.IsAutoSuspend = 0
        order_field.OrderRef = str(self.order_ref)
        
        self.order_ref += 1
        
        return self.ReqOrderInsert(order_field)

    # 数据转换方法
    def _convert_order_to_dict(self, pOrder):
        """将订单对象转换为字典"""
        if not pOrder:
            return {}
        
        return {
            'BrokerID': to_str(pOrder.BrokerID),
            'InvestorID': to_str(pOrder.InvestorID),
            'ExchangeID': to_str(pOrder.ExchangeID),
            'InstrumentID': to_str(pOrder.InstrumentID),
            'OrderRef': to_str(pOrder.OrderRef),
            'UserID': to_str(pOrder.UserID),
            'OrderPriceType': pOrder.OrderPriceType,
            'Direction': pOrder.Direction,
            'CombOffsetFlag': to_str(pOrder.CombOffsetFlag),
            'CombHedgeFlag': to_str(pOrder.CombHedgeFlag),
            'LimitPrice': pOrder.LimitPrice,
            'VolumeTotalOriginal': pOrder.VolumeTotalOriginal,
            'TimeCondition': pOrder.TimeCondition,
            'GTDDate': to_str(pOrder.GTDDate),
            'VolumeCondition': pOrder.VolumeCondition,
            'MinVolume': pOrder.MinVolume,
            'ContingentCondition': pOrder.ContingentCondition,
            'StopPrice': pOrder.StopPrice,
            'ForceCloseReason': pOrder.ForceCloseReason,
            'IsAutoSuspend': pOrder.IsAutoSuspend,
            'OrderLocalID': to_str(pOrder.OrderLocalID),
            'ExchangeInstID': to_str(pOrder.ExchangeInstID),
            'ParticipantID': to_str(pOrder.ParticipantID),
            'ClientID': to_str(pOrder.ClientID),
            'ExchangeOrderID': to_str(pOrder.ExchangeOrderID),
            'TraderID': to_str(pOrder.TraderID),
            'InstallID': pOrder.InstallID,
            'OrderSubmitStatus': pOrder.OrderSubmitStatus,
            'NotifySequence': pOrder.NotifySequence,
            'TradingDay': to_str(pOrder.TradingDay),
            'SettlementID': pOrder.SettlementID,
            'OrderSysID': to_str(pOrder.OrderSysID),
            'OrderSource': pOrder.OrderSource,
            'OrderStatus': pOrder.OrderStatus,
            'OrderType': pOrder.OrderType,
            'VolumeTraded': pOrder.VolumeTraded,
            'VolumeTotal': pOrder.VolumeTotal,
            'InsertDate': to_str(pOrder.InsertDate),
            'InsertTime': to_str(pOrder.InsertTime),
            'ActiveTime': to_str(pOrder.ActiveTime),
            'SuspendTime': to_str(pOrder.SuspendTime),
            'UpdateTime': to_str(pOrder.UpdateTime),
            'CancelTime': to_str(pOrder.CancelTime),
            'ActiveTraderID': to_str(pOrder.ActiveTraderID),
            'ClearingPartID': to_str(pOrder.ClearingPartID),
            'SequenceNo': pOrder.SequenceNo,
            'FrontID': pOrder.FrontID,
            'SessionID': pOrder.SessionID,
            'UserProductInfo': to_str(pOrder.UserProductInfo),
            'StatusMsg': to_str(pOrder.StatusMsg),
            'UserForceClose': pOrder.UserForceClose,
            'ActiveUserID': to_str(pOrder.ActiveUserID),
            'BrokerOrderSeq': pOrder.BrokerOrderSeq,
            'RelativeOrderSysID': to_str(pOrder.RelativeOrderSysID),
            'ZCETotalTradedVolume': pOrder.ZCETotalTradedVolume,
            'IsSwapOrder': pOrder.IsSwapOrder,
            'BranchID': to_str(pOrder.BranchID),
            'InvestUnitID': to_str(pOrder.InvestUnitID),
            'AccountID': to_str(pOrder.AccountID),
            'CurrencyID': to_str(pOrder.CurrencyID),
            'IPAddress': to_str(pOrder.IPAddress),
            'MacAddress': to_str(pOrder.MacAddress)
        }

    def _convert_trade_to_dict(self, pTrade):
        """将成交对象转换为字典"""
        if not pTrade:
            return {}
        
        return {
            'BrokerID': to_str(pTrade.BrokerID),
            'InvestorID': to_str(pTrade.InvestorID),
            'ExchangeID': to_str(pTrade.ExchangeID),
            'InstrumentID': to_str(pTrade.InstrumentID),
            'OrderRef': to_str(pTrade.OrderRef),
            'UserID': to_str(pTrade.UserID),
            'TradeID': to_str(pTrade.TradeID),
            'Direction': pTrade.Direction,
            'OrderSysID': to_str(pTrade.OrderSysID),
            'ParticipantID': to_str(pTrade.ParticipantID),
            'ClientID': to_str(pTrade.ClientID),
            'TradingRole': pTrade.TradingRole,
            'ExchangeInstID': to_str(pTrade.ExchangeInstID),
            'OffsetFlag': pTrade.OffsetFlag,
            'HedgeFlag': pTrade.HedgeFlag,
            'Price': pTrade.Price,
            'Volume': pTrade.Volume,
            'TradeDate': to_str(pTrade.TradeDate),
            'TradeTime': to_str(pTrade.TradeTime),
            'TradeType': pTrade.TradeType,
            'PriceSource': pTrade.PriceSource,
            'TraderID': to_str(pTrade.TraderID),
            'OrderLocalID': to_str(pTrade.OrderLocalID),
            'ClearingPartID': to_str(pTrade.ClearingPartID),
            'BusinessUnit': to_str(pTrade.BusinessUnit),
            'SequenceNo': pTrade.SequenceNo,
            'TradingDay': to_str(pTrade.TradingDay),
            'SettlementID': pTrade.SettlementID,
            'BrokerOrderSeq': pTrade.BrokerOrderSeq,
            'TradeSource': pTrade.TradeSource,
            'InvestUnitID': to_str(pTrade.InvestUnitID),
        }

    def _convert_order_action_to_dict(self, pOrderAction):
        """将撤单对象转换为字典"""
        if not pOrderAction:
            return {}
        
        return {
            'BrokerID': to_str(pOrderAction.BrokerID),
            'InvestorID': to_str(pOrderAction.InvestorID),
            'OrderActionRef': pOrderAction.OrderActionRef,
            'OrderRef': to_str(pOrderAction.OrderRef),
            'RequestID': pOrderAction.RequestID,
            'FrontID': pOrderAction.FrontID,
            'SessionID': pOrderAction.SessionID,
            'ExchangeID': to_str(pOrderAction.ExchangeID),
            'OrderSysID': to_str(pOrderAction.OrderSysID),
            'ActionFlag': pOrderAction.ActionFlag,
            'LimitPrice': pOrderAction.LimitPrice,
            'VolumeChange': pOrderAction.VolumeChange,
            'UserID': to_str(pOrderAction.UserID),
            'InstrumentID': to_str(pOrderAction.InstrumentID),
            'InvestUnitID': to_str(pOrderAction.InvestUnitID),
            'IPAddress': to_str(pOrderAction.IPAddress),
            'MacAddress': to_str(pOrderAction.MacAddress)
        }


class ReqInstrumentApi(TraderApiBase):
    """查询合约信息的API"""
    
    def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None,
                 page_dir='', private_resume_type=2, public_resume_type=2, productclass = '1'):
        """ productclass 为None时 不过滤合约类型，否则只返回指定产品类型的合约 """
        super().__init__(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue,
                        page_dir, private_resume_type, public_resume_type)
        self.instrument_id_list = []
        #self.instrument_commission_list = []
        self.productclass = productclass

    def req_qry_instrumrent_id(self):
        """查询合约ID"""
        qry_instrument_field = traderapi.CThostFtdcQryInstrumentField()
        self.ReqQryInstrument(qry_instrument_field)
    
    def req_qry_instrument_commission_rate(self):
        """查询合约手续费"""
        qry_instrument_commission_rate_field = traderapi.CThostFtdcQryInstrumentCommissionRateField()
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        qry_instrument_commission_rate_field.BrokerID = broker_id
        qry_instrument_commission_rate_field.InvestorID = investor_id
        self.ReqQryInstrumentCommissionRate(qry_instrument_commission_rate_field)

    def OnRspQryInstrument(self, pInstrument, pRspInfo, nRequestID, bIsLast):
        """查询合约响应"""
        if not pRspInfo or pRspInfo.ErrorID == 0:
            if pInstrument:
                #print(pInstrument.to_dict())
                # 将 pInstrument 转换为字典，保存完整的合约数据
                try:
                    instrument_dict = self._convert_instrument_to_dict(pInstrument)
                except Exception as e:
                    logger.error(f"Error converting instrument to dict: {e}")
                    #print(f"pInstrument type: {type(pInstrument)}")
                    instrument_dict = {}
                
                # 创建 qry_instrument_field = traderapi.CThostFtdcInstrumentField()
                #ins = traderapi.CThostFtdcInstrumentField()
                #traderapi.CopyCThostFtdcInstrumentField(ins, pInstrument)

                try:
                    instrument_id = to_str(pInstrument.InstrumentID)
                    # 过滤有效的合约ID
                    # if (instrument_id[-4:].isdigit() and instrument_id[:-4].isalpha()) or \
                    #    (instrument_id[-3:].isdigit() and instrument_id[:-3].isalpha()):
                    
                    #匹配类型 
                    if self.productclass is None or instrument_dict['ProductClass'] == self.productclass :
                        # 保存原始对象和完整数据字典
                        self.instrument_id_list.append(instrument_id)
                        # 如果需要保存完整数据字典，可以添加到另一个列表中
                        if not hasattr(self, 'instrument_data_list'):
                            self.instrument_data_list = []
                        self.instrument_data_list.append(instrument_dict)
                        #print(f"收到合约: {instrument_id}")  # 添加调试信息
                except Exception as e:
                    logger.error(f"Error processing instrument ID: {e}")
                    #print(f"pInstrument type: {type(pInstrument)}")
        else:
            if pRspInfo:
                logger.error(f"查询合约失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")

        if bIsLast:
            logger.info(f"合约查询完成，共收到 {len(self.instrument_id_list)} 个合约")
            self.status = 2  # 直接设置为完成状态

            # 查询 合约的手续费 
            #self.req_qry_instrument_commission_rate()
        else:
            self.status = 1  # 查询进行中




    def OnRspSettlementInfoConfirm(self, pSettlementInfoConfirm, pRspInfo, nRequestID, bIsLast):
        """确认结算信息响应 - 重写以开始查询合约"""
        if pRspInfo and pRspInfo.ErrorID != 0:
            logger.error(f"确认结算信息失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")
        else:
            logger.info("确认结算信息成功，开始查询合约")
            # 开始查询合约
            self.req_qry_instrumrent_id()

    def Join(self):
        """等待查询完成并返回合约列表"""
        while True:
            if self.status == 0:
                # 等待登录完成
                sleep(1)
            elif self.status == 1:
                # 等待查询完成
                sleep(1)
            elif self.status == 2:
                #return self.instrument_id_list
                self.Release()
                return self.instrument_id_list
            else:
                sleep(1)
    
    def Join_with_full_data(self):
        """等待查询完成并返回完整的合约数据字典列表"""
        while True:
            if self.status == 0:
                # 等待登录完成
                sleep(1)
            elif self.status == 1:
                # 等待查询完成
                sleep(1)
            elif self.status == 2:
                self.Release()
                return getattr(self, 'instrument_data_list', [])
            else:
                sleep(1)



class ReqComissionRateApi(TraderApiBase):
    """查询合约信息的API"""
    
    def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None,
                 page_dir='', product_list=[], req_commission_rate=False, req_order_commission=False, private_resume_type=2, public_resume_type=2):
        super().__init__(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue,
                        page_dir, private_resume_type, public_resume_type)
        #self.instrument_id_list = []
        self.product_list = product_list # 品种列表

        # 将  instrument_commissionrate_list 初始化 个数为 len(product_list)， 每个元素为None 的列表
        self.instrument_commissionrate_list = [None] * len(self.product_list) # 合约手续费列表  
        self.commissionrate_qry_id = -1 # 手续费查询操作 序号
        self.valid_count = 0
        self.comm_op_state = 0 # 操作状态 0：ok  -2，表示未处理请求超过许可数； -3，表示每秒发送请求数超过许可数。 

        self.instrument_order_commissionrate_list = [None] * len(self.product_list) # 合约报单手续费列表  
        self.order_commissionrate_qry_id = -1 # 报单手续费查询操作 序号 
        self.order_commissionrate_valid_count = 0
        self.order_comm_op_state = 0 # 操作状态 0：ok  -2，表示未处理请求超过许可数； -3，表示每秒发送请求数超过许可数。
        self.req_commission_rate = req_commission_rate
        self.req_order_commission = req_order_commission

    def req_qry_instrumrent_id(self):
        """查询合约ID"""
        qry_instrument_field = traderapi.CThostFtdcQryInstrumentField()
        self.ReqQryInstrument(qry_instrument_field)

    def req_instrument_commissionrate(self):
        if self.commissionrate_qry_id == -1:
            if len(self.product_list) > 0:
                self.commissionrate_qry_id = 0
        elif self.commissionrate_qry_id < 0 or  self.commissionrate_qry_id >= len(self.product_list):
            return True # 查询结束

        if self.product_list[self.commissionrate_qry_id] is None:
            self.commissionrate_qry_id = -2 
            return False
            
        qry_field = traderapi.CThostFtdcQryInstrumentCommissionRateField()
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        qry_field.BrokerID = broker_id
        qry_field.InvestorID = investor_id
        qry_field.InstrumentID = self.product_list[self.commissionrate_qry_id] 
        self.comm_op_state  = self.ReqQryInstrumentCommissionRate(qry_field)
        #print("eq_instrument_commissionrate():",self.comm_op_state )
        return None

    def req_qry_instrument_order_commission_rate(self):
        """查询合约报单手续费"""
        if self.order_commissionrate_qry_id == -1:
            if len(self.product_list) > 0:
                self.order_commissionrate_qry_id = 0
        elif self.order_commissionrate_qry_id < 0 or  self.order_commissionrate_qry_id >= len(self.product_list):
            return True # 查询结束

        if self.product_list[self.order_commissionrate_qry_id] is None:
            self.order_commissionrate_qry_id = -2   
            return False

        qry_field = traderapi.CThostFtdcQryInstrumentOrderCommRateField()
        broker_id = self.broker_id.decode() if isinstance(self.broker_id, bytes) else self.broker_id
        investor_id = self.investor_id.decode() if isinstance(self.investor_id, bytes) else self.investor_id
        qry_field.BrokerID = broker_id
        qry_field.InvestorID = investor_id
        qry_field.InstrumentID = self.product_list[self.order_commissionrate_qry_id] 
        self.order_comm_op_state  = self.ReqQryInstrumentOrderCommRate(qry_field)
        #print("req_qry_instrument_order_commission_rate:",self.order_comm_op_state, qry_field.InstrumentID)


    def OnRspQryInstrument(self, pInstrument, pRspInfo, nRequestID, bIsLast):
        """查询合约响应"""
        if not pRspInfo or pRspInfo.ErrorID == 0:
            if pInstrument:
                # 将 pInstrument 转换为字典，保存完整的合约数据
                try:
                    instrument_dict = self._convert_instrument_to_dict(pInstrument)
                except Exception as e:
                    logger.error(f"Error converting instrument to dict: {e}")
                    #print(f"pInstrument type: {type(pInstrument)}")
                    instrument_dict = {}

                try:
                    instrument_id = to_str(pInstrument.InstrumentID)
                    # 过滤有效的合约ID
                    if (instrument_id[-4:].isdigit() and instrument_id[:-4].isalpha()) or \
                       (instrument_id[-3:].isdigit() and instrument_id[:-3].isalpha()):
                        # 保存原始对象和完整数据字典
                        self.instrument_id_list.append(instrument_id)
                        # 如果需要保存完整数据字典，可以添加到另一个列表中
                        if not hasattr(self, 'instrument_data_list'):
                            self.instrument_data_list = []
                        self.instrument_data_list.append(instrument_dict)
                        #print(f"收到合约: {instrument_id}")  # 添加调试信息
                except Exception as e:
                    logger.error(f"Error processing instrument ID: {e}")
                    #print(f"pInstrument type: {type(pInstrument)}")
        else:
            if pRspInfo:
                logger.error(f"查询合约失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")

        if bIsLast:
            logger.info(f"合约查询完成，共收到 {len(self.instrument_id_list)} 个合约")
            self.status = 2  # 直接设置为完成状态
        else:
            self.status = 1  # 查询进行中

    def OnRspQryInstrumentCommissionRate(self, pInstrumentCommissionRate, pRspInfo, nRequestID, bIsLast):

        # if not debugpy.is_client_connected():
        #     debugpy.wait_for_client()  # 阻塞等待调试器连接
        # debugpy.breakpoint()  # 强制断点

        """ 请求查询手续费响应 """ 
        if pRspInfo is None or pRspInfo.ErrorID == 0:
            if pInstrumentCommissionRate:
                #print(pInstrumentCommissionRate.to_dict())
                # 将 pInstrumentCommissionRate 转换为字典，保存完整的合约数据
                try:
                    commissionrate_dict = self._convert_commissionRate_to_dict(pInstrumentCommissionRate)
                except Exception as e:
                    logger.error(f"Error converting instrument to dict: {e}")
                    #print(f"pInstrumentCommissionRate type: {type(pInstrumentCommissionRate)}")
                    commissionrate_dict = {}
                
                try:
                    instrument_id = to_str(pInstrumentCommissionRate.InstrumentID)
                    # 过滤有效的合约ID
                    #if commissionrate_dict['InstrumentID'] in self.instrument_id_list :
                    # 保存原始对象和完整数据字典
                    if self.commissionrate_qry_id >=0 and self.commissionrate_qry_id < len(self.product_list):
                        # 如果需要保存完整数据字典，可以添加到另一个列表中
                        self.instrument_commissionrate_list[self.commissionrate_qry_id] = commissionrate_dict
                        self.valid_count += 1
                        #print(f"收到合约: {instrument_id}")  # 添加调试信息
                except Exception as e:
                    logger.error(f"Error processing instrument ID: {e}")
                    #print(f"pInstrumentCommissionRate type: {type(pInstrumentCommissionRate)}")
               
        else:
            if pRspInfo:
                logger.error(f"查询品种手续费失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")

        self.commissionrate_qry_id += 1

        if bIsLast:
            if self.status < 1:
                self.status = 1
            #ret =  self.req_instrument_commissionrate()
            #if ret is not None :
            if self.commissionrate_qry_id == len(self.product_list):
                logger.info(f"手续费查询完成，  {self.valid_count} / {len(self.product_list)}  ")
                
                if self.req_order_commission:
                    self.status = 2  # 直接设置为完成状态
                    ret = self.req_qry_instrument_order_commission_rate()   
                else:
                    self.status = 4  # 直接设置为完成状态

        else:
            self.status = 1  # 查询进行中
            
    def OnRspQryInstrumentOrderCommRate(self, pInstrumentOrderCommRate, pRspInfo, nRequestID, bIsLast):

        # if not debugpy.is_client_connected():
        #     debugpy.wait_for_client()  # 阻塞等待调试器连接
        # debugpy.breakpoint()  # 强制断点

        """ 请求查询手续费响应 """ 
        if pRspInfo is None or pRspInfo.ErrorID == 0:
            if pInstrumentOrderCommRate:
                # 将 pInstrumentOrderCommRate 转换为字典，保存完整的合约数据
                try:
                    commissionrate_dict = self._convert_order_commission_to_dict(pInstrumentOrderCommRate)
                except Exception as e:
                    logger.error(f"Error converting instrument to dict: {e}")
                    #print(f"pInstrumentOrderCommRate type: {type(pInstrumentOrderCommRate)}")
                    commissionrate_dict = {}
                
                try:
                    instrument_id = to_str(pInstrumentOrderCommRate.InstrumentID)
                    if self.order_commissionrate_qry_id >=0 and self.order_commissionrate_qry_id < len(self.product_list):
                        # 如果需要保存完整数据字典，可以添加到另一个列表中
                        self.instrument_order_commissionrate_list[self.order_commissionrate_qry_id] = commissionrate_dict
                        self.order_commissionrate_valid_count += 1
                        #print(f"收到合约: {instrument_id}")  # 添加调试信息
                except Exception as e:
                    logger.error(f"Error processing instrument ID: {e}")
                    #print(f"pInstrumentOrderCommRate type: {type(pInstrumentOrderCommRate)}")               
        else:
            if pRspInfo:
                logger.error(f"查询品种报单手续费失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")

        self.order_commissionrate_qry_id += 1
        if bIsLast:
            if self.status < 3:
                self.status = 3
            #ret = self.req_qry_instrument_order_commission_rate()      
            if self.order_commissionrate_qry_id == len(self.product_list):  
                logger.info(f"报单手续费查询完成，  {self.order_commissionrate_valid_count} / {len(self.product_list)}  ")
                self.status = 4  # 直接设置为完成状态
        else:
            self.status = 3  # 查询进行中

    def OnRspSettlementInfoConfirm(self, pSettlementInfoConfirm, pRspInfo, nRequestID, bIsLast):
        """确认结算信息响应 - 重写以开始查询合约"""
        if pRspInfo and pRspInfo.ErrorID != 0:
            logger.error(f"确认结算信息失败: {pRspInfo.ErrorID} - {to_str(pRspInfo.ErrorMsg)}")
        else:
            logger.info("确认结算信息成功，开始查询手续费")
            # 开始查询合约
            if self.req_commission_rate:
                self.status = 1
                self.req_instrument_commissionrate()
            elif self.req_order_commission:
                self.status = 3
                self.req_qry_instrument_order_commission_rate()
            else:
                logger.warning(" 查询任务为空， 请设置 req_commission_rate 或 req_order_commission")
                self.status = 4

    def Join(self):
        """等待查询完成并返回合约列表"""
        while True:
            if self.status == 0:
                # 等待登录完成
                sleep(1)
            elif self.status == 1:
                # 等待查询完成
                sleep(1)
            elif self.status == 2:
                self.Release()
                return self.instrument_id_list
            else:
                sleep(1)
    
    def Join_with_full_data(self):
        """等待查询完成并返回完整的合约数据字典列表"""
        while True:
            if self.status == 0:
                # 等待登录完成
                sleep(1)
            elif self.status == 1:
                # 等待查询完成
                if self.commissionrate_qry_id < len(self.product_list):  
                    self.req_instrument_commissionrate()
                sleep(0.5)
            elif self.status == 3 or self.status == 2:
                # 等待查询完成
                if self.order_commissionrate_qry_id < len(self.product_list):  
                    self.req_qry_instrument_order_commission_rate()
                sleep(0.5)
            elif self.status == 4:
                # 返回完整的合约数据字典列表，如果不存在则返回空列表
                self.Release()
                return (self.instrument_commissionrate_list,self.instrument_order_commissionrate_list)
            else:
                sleep(1)




# 便利函数
def run_traderapi(account, md_queue=None):
    """运行交易API"""
    # 检查account是否有必要的属性
    if hasattr(account, 'broker_id') and hasattr(account, 'server_dict'):
        trader_engine = TraderApi(
            account.broker_id,
            account.server_dict['TDServer'],
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            md_queue,
            getattr(account, 'td_page_dir', '')
        )
        trader_engine.Join()
    else:
        # 如果account不是FutureAccount类型，直接使用参数
        trader_engine = TraderApi(
            account.broker_id,
            account.td_server,
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            md_queue,
            getattr(account, 'page_dir', '')
        )
        trader_engine.Join()


def req_instrument(account):
    """查询合约信息"""
    # 检查account是否有必要的属性
    if hasattr(account, 'broker_id') and hasattr(account, 'server_dict'):
        trader_engine = ReqInstrumentApi(
            account.broker_id,
            account.server_dict['TDServer'],
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            None,
            getattr(account, 'td_page_dir', '')
        )
        return trader_engine.Join()
    else:
        # 如果account不是FutureAccount类型，直接使用参数
        trader_engine = ReqInstrumentApi(
            account.broker_id,
            account.td_server,
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            None,
            getattr(account, 'page_dir', '')
        )
        return trader_engine.Join()


def req_instrument_full_data(account, productclass='1'):
    """查询合约信息并返回完整数据"""
    # 检查account是否有必要的属性
    if hasattr(account, 'broker_id') and hasattr(account, 'server_dict'):
        trader_engine = ReqInstrumentApi(
            account.broker_id,
            account.server_dict['TDServer'],
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            None,
            getattr(account, 'td_page_dir', ''),
            productclass = productclass
        )
        return trader_engine.Join_with_full_data()
    else:
        # 如果account不是FutureAccount类型，直接使用参数
        trader_engine = ReqInstrumentApi(
            account.broker_id,
            account.td_server,
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            None,
            getattr(account, 'page_dir', ''),
            productclass = productclass
        )
        return trader_engine.Join_with_full_data()


def req_instrument_commissionrate_data(account, product_list, req_commission_rate=False, req_order_commission=False):
    """查询合约手续费信息"""
    # 检查account是否有必要的属性
    if hasattr(account, 'broker_id') and hasattr(account, 'server_dict'):
        trader_engine = ReqComissionRateApi(
            account.broker_id,
            account.server_dict['TDServer'],
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            None,
            getattr(account, 'td_page_dir', ''),
            product_list,
            req_commission_rate=req_commission_rate,
            req_order_commission=req_order_commission
        )
        return trader_engine.Join_with_full_data()
    else:
        # 如果account不是FutureAccount类型，直接使用参数
        trader_engine = ReqComissionRateApi(
            account.broker_id,
            account.td_server,
            account.investor_id,
            account.password,
            account.app_id,
            account.auth_code,
            None,
            getattr(account, 'page_dir', ''),
            product_list,
            req_commission_rate=req_commission_rate,
            req_order_commission=req_order_commission
        )
        return trader_engine.Join_with_full_data()

if __name__ == '__main__':
    # 测试代码
    logger.info("TraderApi_pyctp 已创建完成")